﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace KeyFile
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            byte[] keys = null;
            DirectoryInfo folder = null;
            FileInfo[] allasbs = null;

            if (args.Length > 0) //创建文件, 0  或123
            {
                var folderDialog= new FolderBrowserDialog();
                if (folderDialog.ShowDialog() == DialogResult.OK)
                {
                    var path = Path.Combine(folderDialog.SelectedPath, string.Format("{0}.dat", args[0]));
                    using (var sw = File.OpenWrite(path))
                    {

                        if (args[0].Equals("0")) //生成 0 文件
                        {
                            var bytes = ASCIIEncoding.ASCII.GetBytes("m");
                            sw.Write(bytes, 0, bytes.Length);
                            bytes = ASCIIEncoding.ASCII.GetBytes("a");
                            sw.Write(bytes, 0, bytes.Length);
                            bytes = ASCIIEncoding.ASCII.GetBytes("r");
                            sw.Write(bytes, 0, bytes.Length);
                            bytes = ASCIIEncoding.ASCII.GetBytes("k");
                            sw.Write(bytes, 0, bytes.Length);
                            for (int i = 0; i < 18311836; i++)
                            {
                                sw.WriteByte((Byte.MinValue));
                            }
                        }
                        else if (args[0].Equals("123"))//生成mark123  文件
                        {
                            var bytes = ASCIIEncoding.ASCII.GetBytes("m");
                            sw.Write(bytes, 0, bytes.Length);
                            bytes = ASCIIEncoding.ASCII.GetBytes("a");
                            sw.Write(bytes, 0, bytes.Length);
                            bytes = ASCIIEncoding.ASCII.GetBytes("r");
                            sw.Write(bytes, 0, bytes.Length);
                            bytes = ASCIIEncoding.ASCII.GetBytes("k");
                            sw.Write(bytes, 0, bytes.Length);

                            for (int i = 0; i < 4000; i++)
                            {
                                sw.WriteByte((byte)i);
                            }
                        }
                        else if (args[0].Equals("0123")) //将两个文件异或
                        {
                            byte[] bytes0 = null;
                            byte[] bytes123 = null;
                            var ofdl = new OpenFileDialog();
                            if (ofdl.ShowDialog() == DialogResult.OK)
                            {
                                bytes0 = File.ReadAllBytes(ofdl.FileName);
                            }
                            if (ofdl.ShowDialog() == DialogResult.OK)
                            {
                                bytes123 = File.ReadAllBytes(ofdl.FileName);
                            }
                            for (int i = 0; i < bytes0.Length; i++)
                            {
                                sw.WriteByte((byte)(bytes0[i] ^ bytes123[i]));
                            }
                        }
                        else if (args[0].Equals("test"))
                        {
                            byte[] keyBytes = null;//64的key
                            byte[] originBytes = null;//需要解密的文件 剥离无用数据后的
                            var ofdl = new OpenFileDialog();
                            if (ofdl.ShowDialog() == DialogResult.OK)
                            {
                                keyBytes = File.ReadAllBytes(ofdl.FileName);
                            }
                            if (ofdl.ShowDialog() == DialogResult.OK)
                            {
                                originBytes = File.ReadAllBytes(ofdl.FileName);
                            }
                            int num = 0;
                            for (int i = 0; i < originBytes.Length; i++)
                            {
                                if (num >= keyBytes.Length)
                                {
                                    num = 0;
                                }
                                sw.WriteByte((byte)(originBytes[i] ^ keyBytes[num++]));
                            }
                        }
                        else if (args[0].Equals("testKey"))
                        {
                            //var keyPath = @"C:\WORK\Tools\testkey_1\key.dump";
                            //var abfolder = @"C:\WORK\Tools\testkey_1\assetbundle\global-metadata.dat";
                            //var keyss = File.ReadAllBytes(keyPath);
                            //var origins = File.ReadAllBytes(abfolder);
                            //var pures = GetPureData(origins);
                            Console.WriteLine("输入index,输出返回标志，输入-1 退出:");
                            int line = 0;
                            while (line!=-1)
                            {
                                line =int.Parse(Console.ReadLine());
                                Console.WriteLine(string.Format("{0},{1}",line, ByteLegally(line)));
                            }
                           Console.WriteLine("输入任意键退出!");
                           Console.ReadKey(true);
                        }
                    }
                }
                return;
            }

            //批量导出bundle
            var ofd = new OpenFileDialog();
            ofd.Filter = "KeyFile|*.*";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                keys = File.ReadAllBytes(ofd.FileName);

                var abf = new FolderBrowserDialog();
                if (abf.ShowDialog() == DialogResult.OK)
                {
                    folder = new DirectoryInfo(abf.SelectedPath);
                    allasbs = folder.GetFiles("*.asb", SearchOption.AllDirectories);
                    if (allasbs == null || allasbs.Length <= 0)
                    {
                        return;
                    }

                    ParseAsb(keys, allasbs);
                }
                else
                {
                    return;
                }
            }
            else
            {
                return;
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey(true);
        }
        private static void ParseAsb(byte[] key,FileInfo[] orgs)
        {
            byte[] orgBytes = null;
            foreach (var item in orgs)
            {
                orgBytes = File.ReadAllBytes(item.FullName);
                ParseOneFile(key, orgBytes, GetOutputName(item.FullName));
            }
        }
        private static string GetOutputName(string fullName)
        {
            var fileName = Path.GetFileNameWithoutExtension(fullName);
            var fileFolder = Path.GetDirectoryName(fullName);
            return Path.Combine(fileFolder, fileName + "_0.ab");
        }
        private static void ParseOneFile(byte[] key, byte[] orgBytes,string path)
        {
           
            var pureData = GetPureData(orgBytes);

            byte[] result = new byte[pureData.Length];
            int num = 0;
            for (int i = 0; i < pureData.Length; i++)
            {
                if (num >= key.Length)
                {
                    num = 0;
                }
                result[i] =(byte)(pureData[i]^key[num++]);//将数据和key循环异或
            }

            using (var file = File.OpenWrite(path))
            {
                file.Write(result, 0, result.Length);
            }
            Console.WriteLine(string.Format("FilePath:{0},size:{1}" , path, pureData.Length/1024f));
        }

        /// <summary>
        ///  通过文件结构去除无用数据获取实际文件
        /// </summary>
        /// <param name="orgBytes"></param>
        /// <returns></returns>
        private static byte[] GetPureData(byte[] orgBytes)
        {
            List<byte> result = new List<byte>();
            for (int i = 0; i < orgBytes.Length; i++)
            {
                if (i > 3) //去掉文件头
                {
                    var bo = ByteLegally(i - 3);
                    if (bo)
                    {
                        result.Add(orgBytes[i]);
                    }
                }
            }
            Console.WriteLine("allNumBytes:"+ result.Count);
            return result.ToArray();
        }
        const int  bigLoopBytes = 0xA14;    //大循环
        const int blockBytes = 0x264;       //四大块的一块
        const int litterBlockBytes = 0x70;  //小块
        private static bool ByteLegally(int index)
        {
            var loops = index / bigLoopBytes;
            var loopsl = index % bigLoopBytes;
            var block4all = blockBytes * 4 + 4 * 4;
            var oneblock = blockBytes + 4;

            //分析余数
            if (loopsl > block4all || loopsl==0)//小块
            {
                if (loopsl == 0)
                    return false;
                var notblock = loopsl - block4all; //去掉大块 剩余的小块
                if (notblock > litterBlockBytes) //四个无用数据
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            else//在四大块里
            {
                var blockl = loopsl % oneblock; //剩余的一个block
                if (blockl > blockBytes || blockl==0)//4个无用数据里
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }
    }

}
